using LispLib;
using System;
using System.Collections.Generic;
using System.Text;

namespace Noein.GeneticAlgorithm.New
{
    public abstract class Crossover
    {
        protected Selector selector;
        //protected float rate;
        
        public Crossover(Selector selector)//, float rate)
        {
            this.selector = selector;
            //this.rate = rate;
        }

        public abstract List<Individual> Reproduce(List<Individual> pop, int count);
    }

    public class NodeSwap : Crossover
    {
        private Interpreter interpreter = new Interpreter();
        private Random rand = new Random();

        public NodeSwap(Selector selector)
            : base(selector)
        {
        }

        public override List<Individual> Reproduce(List<Individual> pop, int count)
        {
            List<Individual> offsprings = new List<Individual>();

            List<Interpreter.Pair> geno1 = null;
            List<Interpreter.Pair> geno2 = null;
            for (int i = 0; i < count; i++)
            {
                if (i % 2 == 0)
                {
                    geno1 = new List<Interpreter.Pair>();
                    geno2 = new List<Interpreter.Pair>();

                    // select parents
                    List<Individual> parents = selector.Select(pop, 2);

                    for (int j = 0; j < parents[0].Genotype.Count; j++)
                    {
                        Interpreter.Pair p1Geno = parents[0].Genotype[j];
                        Interpreter.Pair p2Geno = parents[1].Genotype[j];

                        // duplicate parents' genotypes
                        Interpreter.Pair geno12 = Interpreter.Pair.Clone(p1Geno);
                        Interpreter.Pair geno22 = Interpreter.Pair.Clone(p2Geno);

                        geno1.Add(geno12);
                        geno2.Add(geno22);

                        // flatten parsed trees into arrays
                        List<Interpreter.Pair> p1List = new List<Interpreter.Pair>();
                        List<Interpreter.Pair> p2List = new List<Interpreter.Pair>();
                        interpreter.Flatten(geno12, p1List);
                        interpreter.Flatten(geno22, p2List);

                        // pick a random node to be swapped from each tree
                        Interpreter.Pair p1Point = p1List[rand.Next(0, p1List.Count)];
                        Interpreter.Pair p2Point = p2List[rand.Next(0, p2List.Count)];

                        // swap nodes
                        object p1PointCarBk = p1Point.car_;
                        p1Point.car_ = p2Point.car_;
                        p2Point.car_ = p1PointCarBk;
                    }

                    offsprings.Add(new Individual(geno1));
                }
                else
                {
                    offsprings.Add(new Individual(geno2));
                }
            }

            return offsprings;
        }
    }
}
